/* Copyright 2010 Antonio Ruano Cuesta
 *
 * This program is free software: you can redistribute it and/or modify it under 
 * the terms of the GNU General Public License as published by the Free Software 
 * Foundation, either version 3 of the License, or (at your option) any later 
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with 
 * this program. If not, see <http://www.gnu.org/licenses/>
*/

#include <iostream>
#include <fstream>
#include <new>
#include <ctime>
#include <iomanip>
#include "func_aux.h"

using namespace std;

unsigned int PosMaximo (unsigned int *v, int util_v)
{
	unsigned int *posiciones = new (nothrow) unsigned int [util_v];
	unsigned int util_pos = 0;
	
	unsigned int max = Maximo (v,util_v);

	for (int i = 0 ; i < util_v ; i++)
		if (v[i] == max){
			posiciones[util_pos] = i;
			util_pos++;	
		}

	time_t t;
	//Inicializa el generador de números aleatorios con el reloj del sistema
	srand((unsigned int) time(&t));
	
	return (posiciones[rand() % util_pos]);
}

unsigned int Maximo (unsigned int *v, int util_v)
{
	unsigned int max = 0;	

	for (int i = 0 ; i < util_v ; i++)
		if (v[i] > max)
			max = v[i];

	return max;
}

void IntercambiarEnteros (unsigned int &n1, unsigned int &n2)
{
	unsigned int aux;
	aux = n2;
	n2 = n1;
	n1 = aux;
}

void IntercambiarFloat (float &n1, float &n2)
{
	float aux;
	aux = n2;
	n2 = n1;
	n1 = aux;
}

int BuscaSec_intervalo (unsigned int *v, int i, int j, unsigned int valor)
{
	if (i < j){

		bool seguir = true;
		int pos_encontrado;

		for (int w = i ; w < j && seguir ; w++)
			if (v[w] == valor){
				seguir = false;
				pos_encontrado = w;
			}

		if (!seguir)
			return pos_encontrado;
		else
			return -1;
	}
	else
		return -1;		
}

unsigned int Moda (unsigned int *v, int util_v, unsigned int util_repetidos)
{
	unsigned int *repetidos = new (nothrow) unsigned int [util_repetidos];
	unsigned int *conteos = new (nothrow) unsigned int [util_repetidos];
	unsigned int moda;
	int util_conteos = 0, conteo_parcial = 0, pos_ini = 0;
	bool seguir = true;

	if (util_v > 1){

		util_repetidos = 0;
		repetidos[util_repetidos] = v[0];

		while (seguir){

			pos_ini = BuscaSec_intervalo (v, pos_ini+1, util_v, v[0]);

			if (pos_ini == -1)
				seguir = false;
			else
				conteo_parcial++;
		}

		conteos[util_conteos] = conteo_parcial;
	
		for (int i = 1 ; i < util_v ; i++){

			if (BuscaSec_intervalo (repetidos, 0, util_repetidos, v[i]) == -1){

				util_repetidos++;
				repetidos[util_repetidos] = v[i];

				seguir = true;
				conteo_parcial = 0;
				pos_ini = i;

				while (seguir){

					pos_ini = BuscaSec_intervalo (v, pos_ini+1, util_v, v[i]);

					if (pos_ini == -1)
						seguir = false;
					else
						conteo_parcial++;
				}

				util_conteos++;
				conteos[util_conteos] = conteo_parcial;
			}
		}

		moda = repetidos[PosMaximo(conteos, util_conteos)];
	}
	else
		moda = v[0];

	delete [] conteos;
	delete [] repetidos;

	return moda;
}

float DistEuclidea (float x, float y)
{
	return ((x-y)*(x-y));
}

int SumaFila(int **matriz,int cols,int fila)
{
	int suma = 0;

	for (int i = 0 ; i < cols ; i++)
		suma += matriz[fila][i];

	return suma;
}

int SumaCol(int **matriz,int fils,int columna)
{
	int suma = 0;

	for (int i = 0 ; i < fils ; i++)
		suma += matriz[i][columna];

	return suma;
}

void ImpresionMatrizConfusion(int **confusion,unsigned int dim)
{
	if (dim > 0){

		cout.setf(ios::fixed);
		cout.setf(ios::showpoint);	

		int suma,suma_acum=0;
		float exito_acum=0,media_exito, exito, error;

		cout<<endl;

		for (unsigned int i = 0 ; i < dim ; i++){
			cout<<"\t";
			cout<<"["<<i+1<<"]";
		}

		cout<<"\t"<<"Total"<<"\t"<<"Exito"<<"\t"<<" Error"<<endl;
		
		for (unsigned int i = 0 ; i < dim ; i++){
			
			cout<<"["<<i+1<<"]\t";
			suma = SumaFila(confusion,dim,i);
			suma_acum += suma;
			exito_acum += (confusion[i][i]*100)/(float)suma;

			for (unsigned int j = 0 ; j < dim ; j++){
				cout<<confusion[i][j]<<"\t";
				
			}

			exito = (float)(confusion[i][i]*100)/(float)suma;
			error = 100 - exito;
		
			cout.precision(0);
			cout<<suma<<"\t";
			cout<<setprecision(2)<<setw(5)<<exito<<"\t";
			cout<<setprecision(2)<<setw(5)<<error<<endl;			
			
		}

		cout<<endl<<"Total"<<"\t";

		for (unsigned int i = 0 ; i < dim ; i++)
			cout<<SumaCol(confusion,dim,i)<<"\t";

		media_exito = exito_acum/(float)dim;
		
		cout<<suma_acum<<"\t"<<media_exito<<"\t"<<(100-media_exito)<<endl<<endl;
	}
	else
		cerr<<"No se puede imprimir la matriz de confusion. Dimension incorrecta"<<endl;
}

int **LeerMapaColor (char *fich_map, unsigned int num_clases)
{
	ifstream fi;
	int aux;

	int **mapa = new (nothrow) int *[num_clases];

	for (unsigned int i = 0 ; i < num_clases ; i++)
		mapa[i] = new (nothrow) int [3];

	fi.open (fich_map);

	if (!fi){
		cerr<<"Error en la apertura del fichero "<<fich_map<<"."<<endl;
		exit(1);
	}

	for (unsigned int i = 0 ; i < num_clases ; i++){

		fi>>aux;

		for (int j = 0 ; j < 3 ; j++){
			
			fi>>aux;
			mapa[i][j] = aux;
			
		}
	}

	fi.close();

	return mapa;
}




